/*
 *  Copyright © 2014 CIB Co.Ltd
 *  * All right reserved
 *  * Auther:jin xingwang
 *
 */

package com.wsd.scheduler;

import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

import javax.sql.DataSource;

/**
 * 定时任务配置类
 * @author 靳兴旺
 * @version 2020-7-21
 */
@Configuration
@EnableScheduling
public class QuartzConfiguration {

    /**
     * 继承ApplicationContextAware 获得spring上下文中已经实例化的bean
     * 继承SpringBeanJobFactory
     * 实现任务实例化方式
     */
    public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
            ApplicationContextAware {

        private transient AutowireCapableBeanFactory beanFactory;

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            beanFactory = applicationContext.getAutowireCapableBeanFactory();
        }

        /**
         *
         * @param bundle
         * @return job
         * @throws Exception
         *
         * 注：
         * 将job实例交给spring ioc托管
         * 我们在job实例实现类内可以直接使用spring注入的调用被spring ioc管理的实例
         */

        @Override
        protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
            final Object job = super.createJobInstance(bundle);

            /* 将job实例交付给spring Ioc */
            beanFactory.autowireBean(job);
            return job;
        }
    }

    /**
     * 配置任务工厂实例
     * @param applicationContext
     * @return
     */
    @Bean
    public JobFactory jobFactory (ApplicationContext applicationContext) {
        /* 采用自定义任务工厂整合Spring实例来完成构建任务 */
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }

    /**
     * 配置任务调度器
     * 使用项目的数据源，作为任务的数据源
     * @param jobFactory
     * @param dataSource
     * @return
     */
    @Bean(destroyMethod = "destroy", autowire = Autowire.NO)
    public SchedulerFactoryBean schedulerFactoryBean (JobFactory jobFactory, DataSource dataSource) {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        /* 将spring管理job自定义工厂交由调度器维护 */
        schedulerFactoryBean.setJobFactory(jobFactory);
        /* 设置覆盖已存在的业务 */
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        /* 设置调度器自动运行 */
        schedulerFactoryBean.setAutoStartup(true);
        /* 设置数据源，与项目使用同一数据源 */
        schedulerFactoryBean.setDataSource(dataSource);
        /* 设置上下文 */
        schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
        /* 配置文件位置 */
        schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));
        return schedulerFactoryBean;
    }

}
